﻿using System;
using System.Collections.Generic;
using System.IO;
using CSJ2K.Util.IO;

namespace CSJ2K.Jpc.Segments
{
    /// <summary>Quantization component (QCC)</summary>
    /// <comment>
    /// Function: Describes the quantization used for compressing a particular component. 
    /// Usage: Main and first tile-part header of a given tile. Optional in both the main and 
    ///      tile-part headers. No more than one per any given component may be present in 
    ///      either the main or tile-part headers. If there are multiple tile-parts in a tile, 
    ///      and this marker segment is present, it shall be found only in the first 
    ///      tile-part (TPsot = 0). Optional in both the main and tile-part headers. When used
    ///      in the main header, it overrides the main QCD marker segment for the specific 
    ///      component. When used in the tile-part header, it overrides the main QCD, main 
    ///      QCC, and tile QCD for the specific component. Thus, the order of precedence is 
    ///      the following: 
    ///          Tile-part QCC > Tile-part QCD > Main QCC > Main QCD 
    ///      where the "greater than" sign, >, means that the greater overrides the lessor 
    ///      marker segment. 
    /// Length: Variable depending on the number of quantized elements.
    /// </comment>
    public class QCC : Segment
    {
        /// <summary>The index of the component to which this marker serment relates. (8 or 16 depending on SIZ.C)</summary>
        public ushort C;

        /// <summary>Quantization style for this component</summary>
        public byte S;     
        /// <summary>Quantization step size value for the ith sub-band in the defined order. (8 or 16 bit per element depending on QCC.S)</summary>
        public ushort[] SP;

        public QCC(Stream source, int components)
            : this(source, (Markers)StreamUtil.ReadBUInt16(source), components) { }
        public QCC(Stream source, Markers marker, int components)
            : base(source, marker, true)
        {
            if (marker != Markers.QCC) throw (new ApplicationException("Attempting to create segment of the wrong type."));

            int SPLength = Length - 3;
            if (components < 257) { C = StreamUtil.ReadOctet(source); SPLength -= 1; }
            else { C = StreamUtil.ReadBUInt16(source); SPLength -= 2; }
            S = StreamUtil.ReadOctet(source);
            byte[] buffer = StreamUtil.ReadBytes(source, SPLength);
            if ((S | 0x1F) == 0x00) for (int i = 0; i < buffer.Length; i++) SP[i] = buffer[i];
            else for (int i = 0; i < buffer.Length; i++) SP[i] = BitConverter.ToUInt16(buffer, i * 2);
        }
    }
}

